/*
 * Created on 26.07.2004
 *
 * To change the template for this generated file go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
package org.opencube.oms.tools.generator;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import java.io.File;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.opencube.oms.OMSStructure;
import org.opencube.oms.OMSElement;
import org.opencube.oms.OMSData;
import org.opencube.oms.meta.OMSMetaData;
import org.opencube.oms.meta.Scheme;
import org.opencube.oms.meta.SimpleAttribute;
import org.opencube.oms.meta.DatatypeEnumeration;
import java.util.HashMap;

/**
 * @author cw
 *
 * To change the template for this generated type comment go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
public class ElementGenerator {
/* #### CONFIGURATION ##### 
		SQL_INPUT_ELEMENT_FILE: 	specify the input file for your oms elements 
		SQL_INPUT_META_FILE: 		specify the input file for your oms meta data
		CONNECTION_FOLDER: 			specify the folder of the connection.res 
		CONNECTION_ID: 				specify your connection id
		GENERATE_DUMMY_VALUE: 		specify if dummy (simple/unique) values will generated  
	 */

	private static final String SQL_INPUT_ELEMENT_FILE = "C:/oml/elements.xml";
	private static final String SQL_INPUT_META_FILE = "C:/oml/meta.xml";
	private static final String CONNECTION_FOLDER ="C:/lokale_projekte/cvs_projekte/omscube/src/core/java/oms11/conf";
	private static final String CONNECTION_ID ="web-service_test";
	
	private static final boolean GENERATE_DUMMY_VALUE =true;
/* #### END CONFIGURATION #### */

	private Document metaDoc;
	private Document elementDoc;
	private HashMap elements = new HashMap();
	private HashMap schemes = new HashMap();
	private OMSStructure omsStructure;
	private OMSData omsdata;
	private Document getMetaDoc(){
		 return metaDoc;
	}
	private Document getElementDoc(){
			 return elementDoc;
		}
	public static void main(String[] args) {
		ElementGenerator elmGenerator = new ElementGenerator();
		try {
			elmGenerator.generate(SQL_INPUT_ELEMENT_FILE,SQL_INPUT_META_FILE); 
		}catch(Exception e){
			System.out.println("ERROR OCCURS: Message:"+e.getMessage());
			for (int i=0;i<e.getStackTrace().length;i++){
				System.out.println(e.getStackTrace()[i].toString());
			}
		}
		
	}
	
	private OMSStructure getOmsStructure(){
		return omsStructure;
	}
	private void saveToOms() throws Exception{
		
		OMSData omsdata = getOmsData();
		omsdata.saveOMSStructure(getOmsStructure());	
		System.out.println("Master I saved the structure"); 
		
		
	}
	private void generate(String elementXmlFile,String metaXmlFile) throws Exception{
		try {
			elementDoc = getDocument(elementXmlFile);
			metaDoc = getDocument(metaXmlFile);
			setOmsStructure();
			createElements();
			if (GENERATE_DUMMY_VALUE==true){
				generateDummySimpleValues();
			}
			
			associateElements();
			saveToOms();
			
		}catch(Exception e){
			throw e;
			//System.out.println(e.getCause());
		}
		
	}
	private void associateElements() throws Exception{
		OMSStructure omsStructure =  getOmsStructure();
		Document elementDoc =  getElementDoc();
		String childType = "";
		NodeList nodelist = elementDoc.getElementsByTagName("UML:Association.connection");
		for (int i=0;i<nodelist.getLength();i++){
			for (int j=0;j<nodelist.item(i).getChildNodes().getLength();j++){
				
				Node n = nodelist.item(i).getChildNodes().item(j);
				if (!n.getNodeName().equals("UML:AssociationEnd")){
					continue;
				}
				String aggregation = n.getAttributes().getNamedItem("aggregation").getNodeValue();
				if (aggregation==null){
					System.out.println("error while appending: aggregation is null");
				}
				
				//System.out.println(aggregation + " : " +type + " : "+elm.getDisplayName());
				if (aggregation.equals("none")){
					String childtype = n.getAttributes().getNamedItem("type").getNodeValue();
					String complexAttributeName="";
					try {
						complexAttributeName = n.getAttributes().getNamedItem("name").getNodeValue();
					}catch(Exception ex){
						complexAttributeName="";
					}
					OMSElement child = (OMSElement)elements.get(childtype);
					
					String parenttype = n.getNextSibling().getNextSibling().getAttributes().getNamedItem("type").getNodeValue();
					String parentAggregationType = n.getNextSibling().getNextSibling().getAttributes().getNamedItem("aggregation").getNodeValue();
					
					OMSElement parent = (OMSElement)elements.get(parenttype);
					if (parentAggregationType.equals("composite")){
						parent.compose(complexAttributeName, child);
						System.out.println("composite "+child.getDisplayName()+ " under " + parent.getDisplayName());
					}else if (parentAggregationType.equals("shared")){
						System.out.println("aggregate "+child.getDisplayName()+ " with " + parent.getDisplayName());
						parent.associate(complexAttributeName, child,null);
					}else {
						throw new Exception("no valid aggregationType: "+ parentAggregationType);
					}
										
				}
				
			}
		}
		System.out.println("aggregating done!");
	}
	private void generateDummySimpleValues() throws Exception{
		OMSStructure omsStructure =  getOmsStructure();
		OMSData omsdata = getOmsData();
		OMSMetaData md = omsdata.getMetaData(); 
		OMSElement[] elements = omsStructure.getElements();
		for (int i=0;i<elements.length;i++){
			OMSElement elm = elements[i];
			Scheme s = md.getScheme(elm.getNamespacePath(),elm.getSchemeName());
			
			while (s!=null){
				SimpleAttribute[] saa = s.getSimpleAttributes();
				for (int j=0;j<saa.length;j++){
					SimpleAttribute sa =saa[j];
					DatatypeEnumeration[] dten = sa.getDatatype().getDatatypeEnumerations();
					for (int k =0;k<dten.length;k++){
						if (sa.getDatatype().getType()!='b' && sa.getDatatype().getType()!='c'){
							if (sa.getDatatype().getTypeName().equals("string")){
								elm.setValue(sa.getName(),dten[k].getName(),sa.getName()+ " dt: " +dten[k].getName()+elm.getBookmark());
							}
						}
					}
				}
				s = s.getParentScheme();
			}
		}
	}
	private void createElements() throws Exception{

		Document elementDoc =  getElementDoc();
		NodeList nodelist = elementDoc.getElementsByTagName("UML:ClassifierRole");
		OMSStructure omsStructure =  getOmsStructure();
		for (int i=0;i<nodelist.getLength();i++){
			Node n = nodelist.item(i);
			String ea_stype = getTaggedValue(n,"ea_stype");
			if (!ea_stype.equals("Object")){
				continue;
			}
			
			String classId = getTaggedValue(n,"classifier");
			String objectId = n.getAttributes().getNamedItem("xmi.id").getNodeValue();
			String name;
			try {
				name = n.getAttributes().getNamedItem("name").getNodeValue();
			}catch(Exception ex){
				name ="dummy default";				
			}
			String namespace=null;
			String schemeName = getSchemeById(classId);
			if (schemes.get(schemeName)==null){
				namespace = getNamespaceById(classId);
				schemes.put(schemeName,namespace);
			}else {
				namespace = (String)schemes.get(schemeName);
			}
			System.out.println("schemeName: " +schemeName + " | namespace: " +namespace + " : "+objectId);
			OMSElement elm;
			
			if (elements.get(objectId)==null){
				elm = omsStructure.createElement(namespace,schemeName);
				elm.setDisplayName(name);
				elements.put(objectId,elm);
			}
		}
	}
	private String getTaggedValue(Node n,String tagName){
		NodeList nodelist = n.getChildNodes();
		for (int i=0;i<nodelist.getLength();i++){
			if (nodelist.item(i).getNodeName().equals("UML:ModelElement.taggedValue")){
				NodeList tags = nodelist.item(i).getChildNodes();
				for (int j=0;j<tags.getLength();j++){
					if (tags.item(j).getNodeName().equals("UML:TaggedValue")){
						Node myNode = tags.item(j);
						String classifier = myNode.getAttributes().getNamedItem("tag").getNodeValue();
						if (classifier.equals(tagName)){
							return 	myNode.getAttributes().getNamedItem("value").getNodeValue();			 
						}
					}
				}
			}
		}
		return "";
	}
	private String getSchemeById(String id) throws Exception{
		Document metaDoc = getMetaDoc();
		Node n = metaDoc.getElementById(id);
		try { 
			return n.getAttributes().getNamedItem("name").getNodeValue();
		}catch(Exception e){
			throw new Exception("node for id: " +id+  " is null. maybe you did not specify the dtd in your xmi file");
		}
	}
	
	private String getNamespaceById(String id){
		Document metaDoc = getMetaDoc();
		Node n = metaDoc.getElementById(id);
		Node parent = n; 
		String namespace="";
		while (parent!=null){
			parent = parent.getParentNode();
			if (parent==null){
				break;
			}
			//System.out.println(parent.getNodeName());
			if (parent.getNodeName()=="UML:Package"){
				String packageName = parent.getAttributes().getNamedItem("name").getNodeValue();
				if (!packageName.equals("Logical View") && !packageName.equals("Scheme Datatypes View")){
					namespace = "/"+packageName+namespace;
				}
				
				
			}
		}
		return namespace;
	}
	private void setOmsStructure() throws Exception{
		Document elementDoc =  getElementDoc();
		NodeList nodelist = elementDoc.getElementsByTagName("UML:TaggedValue");
		
		int counts=0;
		HashMap roots = new HashMap();
		String idString="";
		
		for (int i =0;i<nodelist.getLength();i++){
			Node n = nodelist.item(i);
			if (n.getAttributes().getNamedItem("tag").getNodeValue().equals("elm_id")){
				String rootElmId = n.getAttributes().getNamedItem("value").getNodeValue();
				idString+=rootElmId+",";
				String rootObjectId = n.getAttributes().getNamedItem("modelElement").getNodeValue();
				roots.put(rootObjectId,rootElmId);
			
			}
		}
		idString = idString.substring(0,idString.length()-1);
		try {
			OMSData omsdata = getOmsData();
			omsStructure = omsdata.getOMSStructureByWhere("elm_id in ("+idString+")");
		}catch(Exception e){
			System.out.println(e.getMessage());
		}	
		Object[] ks = roots.keySet().toArray();
		for (int i =0;i<ks.length;i++){
			String rootElmId = (String)roots.get(ks[i]);
			OMSElement elm = omsStructure.getElementById(rootElmId);
			if (elm==null){
				throw new Exception("no Element with id: " + rootElmId);
			}
			elements.put(ks[i],elm); 
		}
		
	}
	private OMSData getOmsData() throws Exception{
		if (omsdata==null){
			omsdata = new OMSData( CONNECTION_FOLDER,CONNECTION_ID, 0 );
		}
		
		return omsdata; 
	}
	private Document getDocument( String path )	throws IOException, SAXException, ParserConfigurationException
	{
		DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
		Document doc =  builder.parse( new File( path ) );
		doc.normalize();
		return doc;
	}
	
}
